\chapter{数字总和承诺}\label{chap:pedersen}

为了在隐藏交易金额的同时能够验证交易金额的合法性，我们需要使用数字总和承诺的方法。
使用数字总和承诺，我们就能保证在不知道交易具体金额的情况下，
仍然能够验证一笔交易的输入金额和输出金额是相等的，
也就是这笔交易没有凭空创造出数字货币。

我们首先在\ref{sec:commit}节介绍什么是承诺，然后在\ref{sec:pedersen}节介绍Pedersen承诺，
最后在\ref{sec:amount}节说明如何进行数字总和承诺。

\section{承诺}\label{sec:commit}

一个密码学上的承诺是一种不泄露数值的情况下声明自己拥有的某个数值的方法。
一个常见的承诺方式是哈希值承诺，例如在拍卖行提交报价时，
为了防止自己的报价被其他人窃取，可以将自己报价的哈希值公开。
之后统一展示报价时，大家只要计算展示报价的哈希值是否和公开的哈希值相同即可验证报价是否成立，
同时由于哈希函数的困难特性，我们在公开哈希值后再修改报价的概率是可忽略的。
通过哈希值承诺，我们可以在不泄露真实内容的情况下让大家相信我们已经完成出价的事实。

在数字货币交易中，我们也可以使用承诺做到对交易金额的隐藏。
我们可以对交易金额加密，同时使用非对称加密技术将加密金额的密钥传递给接收者。
这样我们就无法修改伪造数值，同时接收者仍然可以验证收到的金额。

\section{Pedersen承诺}\label{sec:pedersen}

利用承诺，我们可以做到对数值的隐藏，但是验证者需要保证该交易合法，
所以在交易金额被隐藏后仍然还需要有一套机制来保证交易的合法性。
Pedersen承诺\cite{noether2016ring}就是这样一种承诺。一种承诺方案$\mathcal{H}$被叫做Pedersen承诺需要满足加法同态性，即：
%
$$\mathcal{H}(a)+\mathcal{H}(b)=\mathcal{H}(a+b)$$
%
那么我们就能够利用承诺的结果验证交易的真实性。

实际上，许多被区块链采用的哈希方案，例如离散对数、椭圆曲线方法，恰好都满足Pedersen承诺，
我们可以利用这些方法对交易金额进行承诺。需要注意的是，加密货币一般都包含小数，
而这些方法都是基于整数的，所以在加密货币实际交易时，
使用的是加密货币的最小单位为1，而不是一个加密货币为单位。
在接下来的计算中，我们使用椭圆曲线作为承诺方案，该椭圆曲线的单位元为$G$。
进行承诺时，我们会使用一个椭圆曲线上的点$H=\lambda G$，
记该承诺的公式为$C_x=\mathcal{H}(V_x)=V_xH$。

需要注意的是，如果只是简单的使用椭圆曲线等方法，还会碰到查表破解的问题。
例如我交易了$V=10^8$最小单位的加密货币，使用承诺$\mathcal{H}$得到了一个$V$的承诺$C=\mathcal{H}(V)$。
但是由于在$H$固定时任何$V=10^8$的承诺都是不变的，只要我遍历$\mathcal{H}(x)$，
我就能查表得到真实交易金额。为了避免这种情况，
在下一节我们还会引入遮盖方法，避免真实交易金额被查表得到。

\section{数字总和承诺}\label{sec:amount}

如果我们使用一个Pedersen承诺$H$，参考图\ref{fig:transaction}的交易，我们只需要验证：
%
$$C_i^1 + C_i^2 = C_o^1 + C_o^2 + C_c + C_f$$
%
就能知道交易金额是正确的了。

但是如前一节所述，如果只是直接使用椭圆曲线，我们可以查表得到承诺前的金额。
为了避免该金额被查到，我们对承诺方案加入遮罩参数。我们规定新承诺计算的公式为
$C_x=\mathcal{H}(r,V_x)=rG + V_xH$，其中$r$是一个随机数。
由于遮罩参数的存在，现在承诺的金额已经和随机数同分布了，
这样就无法通过查表得到被承诺金额。再根据上述验证公式，
如果验证公式能够通过，则有：
%
$$V_i^1 + V_i^2 + r_i^1 + r_i^2 = V_o^1 + V_o^2 + V_c + V_f + r_o^1 + r_o^2 + r_c + r_f$$
%
其中对于合法交易，$V$必定满足要求。而$r$是随机数，
因此我们只需要随机选取除$r_f$外其他$r$，并通过下式计算$r_f$：
$$r_f = r_i^1 + r_i^2 - \left(r_o^1 + r_o^2 + r_c\right)$$
%
就可以满足要求。在实际操作中，输入资金的$r_i$在生成它的上一笔资金中已经生成，
一般不需要重新生成，直接查询到上次生成的$r_i$即可。

通过该方式承诺后，为了能够让收款方能够检查收到的金额，同时矿工能够确认自己获得的矿工费，
在交易中我们会明文记录矿工费$V_f$，选取的选取的基准点$H$和计算得到的$r_f$。
这样矿工就能够自行计算矿工费的承诺$C_f = r_fG + V_fH$，并和其他承诺一起检查交易金额的正确性。
为了收款方能够查询自己受到款项的金额，我们还需要将交易金额遮罩参数存储下来，
共付款方和收款方查询。以$V_o^1$为例，我们可以使用非对称加密等方法，将$V_o^1$和$r_o^1$加密，
这样当且仅当拥有收款方密钥，才能够查看这笔交易的遮罩参数和真实交易金额。同时，
收款方仍然无法检查其他付款和收款的金额。

